import requests
import logging
import traceback
from typing import Dict, List, Optional, Any
import json
from app.utils.timezone_util import timestamp_ms_to_china

logger = logging.getLogger(__name__)


class GPSApiService:
    """GPS API服务类"""
    
    def __init__(self, api_url: str, api_user: str, api_pwd: str):
        self.api_url = api_url.rstrip('/')
        self.api_user = api_user
        self.api_pwd = api_pwd
        self.session = requests.Session()
        self.login_info = None
        # 设置请求头
        self.session.headers.update({
            'User-Agent': 'GPS-Service/1.0'
        })

    def login(self) -> Dict[str, Any]:
        """
        登录GPS系统
        """
        try:
            login_url = f"{self.api_url}/GetDateServices.asmx/loginSystem"
            params = {
                'LoginName': self.api_user,
                'LoginPassword': self.api_pwd,
                'LoginType': 'ENTERPRISE',
                'language': 'cn',
                'ISMD5': '0',
                'timeZone': '+08',
                'apply': 'APP',
                'loginUrl': 'http://vipapi.18gps.net/'
            }
            
            response = self.session.get(login_url, params=params, timeout=30)
            response.raise_for_status()
            
            result = response.json()
            logger.info(f"GPS登录响应: {result}")
            
            if result.get('success') == 'true':
                self.login_info = result
                return {
                    'success': True,
                    'data': result,
                    'message': '登录成功'
                }
            else:
                return {
                    'success': False,
                    'message': result.get('msg', '登录失败'),
                    'error_code': result.get('errorCode')
                }
                
        except requests.RequestException as e:
            logger.error(f"GPS登录请求失败: {str(e)}")
            return {
                'success': False,
                'message': f'网络请求失败: {str(e)}'
            }
        except Exception as e:
            logger.error(f"GPS登录失败: {str(e)}")
            return {
                'success': False,
                'message': f'登录失败: {str(e)}'
            }
    
    def get_device_list(self) -> Dict[str, Any]:
        """
        获取设备列表
        """
        if not self.login_info or not self.login_info.get('mds'):
            login_result = self.login()
            if not login_result['success']:
                return login_result
        
        try:
            device_url = f"{self.api_url}/GetDateServices.asmx/GetDate"
            params = {
                'method': 'getDeviceList',
                'mds': self.login_info['mds']
            }
            
            response = self.session.get(device_url, params=params, timeout=30)
            response.raise_for_status()
            
            result = response.json()
            logger.info(f"获取设备列表响应: {result}")
            
            if result.get('success') == 'true':
                return {
                    'success': True,
                    'data': result.get('rows', []),
                    'message': '获取设备列表成功'
                }
            else:
                return {
                    'success': False,
                    'message': result.get('errorDescribe', '获取设备列表失败')
                }
                
        except Exception as e:
            logger.error(f"获取设备列表失败: {str(e)}")
            return {
                'success': False,
                'message': f'获取设备列表失败: {str(e)}'
            }
    
    def find_device_by_mac_id(self, mac_id: str) -> Dict[str, Any]:
        """
        根据设备号查找设备信息
        """
        device_result = self.get_device_list()
        if not device_result['success']:
            return device_result
        
        devices = device_result['data']
        for device in devices:
            if device.get('macid') == mac_id:
                return {
                    'success': True,
                    'data': device,
                    'message': '找到设备'
                }
        
        return {
            'success': False,
            'message': f'未找到设备号为 {mac_id} 的设备'
        }
    
    def get_device_current_location(self, mac_id: str) -> Dict[str, Any]:
        """
        获取设备当前位置
        """
        # 先查找设备
        device_result = self.find_device_by_mac_id(mac_id)
        if not device_result['success']:
            return device_result
        
        device_info = device_result['data']
        object_id = device_info.get('objectid')
        
        if not object_id:
            return {
                'success': False,
                'message': '设备信息中缺少objectid'
            }
        
        try:
            location_url = f"{self.api_url}/GetDateServices.asmx/GetDate"
            params = {
                'method': 'getUserAndGpsInfoByIDsUtc',
                'mds': self.login_info['mds'],
                'mapType': 'BAIDU',
                'option': 'cn',
                'user_id': object_id
            }
            
            logger.info(f"请求位置信息，参数: {params}")
            response = self.session.get(location_url, params=params, timeout=30)
            response.raise_for_status()
            
            result = response.json()
            logger.debug(f"获取设备位置原始响应: {result}")
            
            # 检查响应是否包含数据（这个API不返回success字段，直接检查数据）
            if 'key' in result and 'records' in result:
                key_map = result.get('key', {})
                records = result.get('records', [])
                
                logger.debug(f"Key映射: {key_map}")
                logger.debug(f"Records数组长度: {len(records)}")
                
                if records and len(records) > 0:
                    record = records[0]  # 取第一条记录
                    logger.debug(f"第一条记录: {record}")
                    
                    # 解析位置信息
                    location_data = self._parse_current_location_record(record, key_map, device_info)
                    
                    if location_data:
                        return {
                            'success': True,
                            'data': location_data,
                            'message': '获取位置成功'
                        }
                    else:
                        return {
                            'success': False,
                            'message': '位置数据解析失败，记录内容可能不完整或格式不正确'
                        }
                else:
                    return {
                        'success': False,
                        'message': '设备无位置记录，可能设备离线或未定位'
                    }
            else:
                # 检查是否有错误信息
                error_msg = result.get('errorDescribe', '未知错误')
                error_code = result.get('errorCode', 'Unknown')
                
                if result.get('success') == 'false':
                    logger.error(f"GPS API错误: {error_msg} (错误代码: {error_code})")
                    return {
                        'success': False,
                        'message': f'GPS API错误: {error_msg}'
                    }
                else:
                    # 响应格式不符合预期
                    logger.error(f"响应格式异常: {result}")
                    return {
                        'success': False,
                        'message': '响应格式异常，缺少必要的数据字段'
                    }
                
        except Exception as e:
            logger.error(f"获取设备位置失败: {str(e)}")
            return {
                'success': False,
                'message': f'获取设备位置失败: {str(e)}'
            }
    
    def _parse_current_location_record(self, record: List, key_map: Dict, device_info: Dict) -> Optional[Dict[str, Any]]:
        """
        解析当前位置记录
        根据GPS API文档解析数据结构
        """
        try:
            logger.info(f"开始解析位置记录，记录长度: {len(record)}")
            logger.info(f"记录内容: {record}")
            
            # 根据key映射获取各字段的索引位置
            sys_time_idx = key_map.get('sys_time', 0)          # 设备定位时间
            user_name_idx = key_map.get('user_name', 1)        # 设备名称
            jingdu_idx = key_map.get('jingdu', 2)              # GPS经度
            weidu_idx = key_map.get('weidu', 3)                # GPS纬度
            ljingdu_idx = key_map.get('ljingdu', 4)            # 基站经度
            lweidu_idx = key_map.get('lweidu', 5)              # 基站纬度
            su_idx = key_map.get('su', 8)                      # 速度
            status_idx = key_map.get('status', 9)              # 状态
            sim_id_idx = key_map.get('sim_id', 11)             # 设备编号
            precision_idx = key_map.get('precision', 23)       # 精度/定位类型
            
            # 检查记录长度是否足够
            min_required_length = max(sys_time_idx, user_name_idx, jingdu_idx, weidu_idx, 
                                    ljingdu_idx, lweidu_idx, su_idx, sim_id_idx, precision_idx) + 1
            
            if len(record) < min_required_length:
                logger.error(f"记录长度不足，需要至少 {min_required_length} 个字段，实际只有 {len(record)} 个")
                return None
            
            # 获取精度值来判断定位类型
            precision = record[precision_idx] if len(record) > precision_idx else 10
            logger.info(f"精度值: {precision}")
            
            # 根据精度值判断定位方式：10表示GPS定位，其他表示基站/WiFi定位
            is_gps_location = (precision == 10)
            
            # 根据定位类型选择经纬度
            if is_gps_location:
                lng = float(record[jingdu_idx]) if record[jingdu_idx] else 0
                lat = float(record[weidu_idx]) if record[weidu_idx] else 0
                location_type = 'GPS'
            else:
                lng = float(record[ljingdu_idx]) if record[ljingdu_idx] else 0
                lat = float(record[lweidu_idx]) if record[lweidu_idx] else 0
                location_type = 'LBS/WiFi'
            
            logger.info(f"解析得到坐标: 经度={lng}, 纬度={lat}, 定位类型={location_type}")
            
            # 检查坐标是否有效
            if lng == 0 or lat == 0:
                logger.warning("坐标为0，可能设备未定位")
                return None
            
            # 获取设备定位时间（UTC时间戳）
            device_time_timestamp = record[sys_time_idx] if len(record) > sys_time_idx else None
            if device_time_timestamp:
                # 如果时间戳是秒级，转换为毫秒级
                if len(str(int(device_time_timestamp))) <= 10:
                    device_time_timestamp = int(device_time_timestamp) * 1000
                device_time_str = timestamp_ms_to_china(device_time_timestamp).strftime('%Y-%m-%d %H:%M:%S')
            else:
                device_time_str = None
            
            # 获取速度
            speed = float(record[su_idx]) if len(record) > su_idx and record[su_idx] else 0
            
            # 获取设备名称
            device_name = record[user_name_idx] if len(record) > user_name_idx else device_info.get('fullName', '')
            
            # 获取设备编号
            device_id = record[sim_id_idx] if len(record) > sim_id_idx else device_info.get('macid', '')
            
            # 获取状态信息
            status = record[status_idx] if len(record) > status_idx else ''
            
            # 解析设备状态（8位状态码）
            device_status = self._parse_device_status(status)
            
            location_data = {
                'device_time': device_time_str,
                'device_name': str(device_name),
                'device_id': str(device_id),
                'lng': lng,
                'lat': lat,
                'speed': speed,
                'location_type': location_type,
                'precision': precision,
                'timestamp': device_time_timestamp,
                'status': device_status,
                'is_positioned': True  # 能获取到位置说明已定位
            }
            
            # 注意：这里不自动获取地址信息，因为当前位置和地址解析可能使用不同的API配置
            # 地址信息将在后端路由层面单独处理
            logger.info(f"成功解析位置数据: {location_data}")
            return location_data
            
        except Exception as e:
            logger.error(f"解析位置记录失败: {str(e)}")
            import traceback
            traceback.print_exc()
            return None
    
    def _parse_device_status(self, status_str: str) -> Dict[str, Any]:
        """
        解析设备状态字符串
        status: 八个连续的字符组成
        """
        try:
            if not status_str or len(status_str) < 8:
                return {}
            
            return {
                'acc_state': status_str[0] == '1',        # ACC状态
                'protect_state': status_str[1] == '1',    # 设备设防状态
                'oil_state': status_str[2] == '1',        # 油电状态
                'charge_state': status_str[3] == '1',     # 充电状态
                'door_state': status_str[4] == '1',       # 门状态
                'location_state': status_str[5] == '1',   # 定位状态
                'power_state': status_str[6] == '1',      # 主电状态
                'platform_defend': status_str[7] == '1',  # 平台设防状态
                'hidden_state': len(status_str) > 8 and status_str[8] == '1'  # 平台隐身状态
            }
        except Exception as e:
            logger.error(f"解析设备状态失败: {str(e)}")
            return {}
    
    def get_device_history_track(self, mac_id: str, start_time: int, end_time: int) -> Dict[str, Any]:
        """
        获取设备历史轨迹，支持分页获取所有数据
        API限制：每次最多返回1000条数据
        逻辑：如果返回1000条，则继续获取下一页；如果少于1000条，则已获取完成
        """
        if not self.login_info or not self.login_info.get('mds'):
            login_result = self.login()
            if not login_result['success']:
                return login_result
        
        all_points = []
        current_start_time = start_time
        page_count = 0
        max_pages = 9999  # 防止无限循环，最多获取9999页
        
        try:
            while page_count < max_pages:
                page_count += 1
                logger.info(f"获取轨迹数据第 {page_count} 页，时间范围: {current_start_time} - {end_time}")
                
                # 调用单次获取方法
                page_result = self._get_single_page_track(mac_id, current_start_time, end_time)
                
                if not page_result['success']:
                    # 如果是第一页就失败，直接返回错误
                    if page_count == 1:
                        return page_result
                    else:
                        # 如果不是第一页，可能是数据已经获取完成，记录警告并退出循环
                        logger.warning(f"第 {page_count} 页获取失败: {page_result['message']}")
                        break
                
                page_points = page_result['data']
                points_count = len(page_points)
                
                logger.info(f"第 {page_count} 页获取到 {points_count} 个轨迹点")
                
                if points_count == 0:
                    # 没有数据，退出循环
                    logger.info("没有更多轨迹数据")
                    break
                
                # 添加到总结果中
                all_points.extend(page_points)
                
                # 如果少于1000条，说明已经获取完成
                if points_count < 1000:
                    logger.info(f"轨迹数据获取完成，共 {page_count} 页，总计 {len(all_points)} 个轨迹点")
                    break
                
                # 如果等于1000条，需要继续获取下一页
                # 获取当前页最后一个点的时间作为下一页的开始时间
                if page_points:
                    # 按时间戳排序，确保获取最大时间
                    sorted_points = sorted(page_points, key=lambda x: x.get('timestamp', 0))
                    last_timestamp = sorted_points[-1].get('timestamp', current_start_time)
                    
                    # 下一页的开始时间设为当前页最大时间戳 + 1毫秒
                    current_start_time = last_timestamp + 1
                    
                    # 防止开始时间超过结束时间
                    if current_start_time >= end_time:
                        logger.info("开始时间已达到结束时间，停止获取")
                        break
                    
                    logger.info(f"准备获取下一页，新的开始时间: {current_start_time}")
                else:
                    # 没有轨迹点但返回成功，可能数据异常
                    logger.warning("获取到空的轨迹点列表")
                    break
            
            if page_count >= max_pages:
                logger.warning(f"已达到最大页数限制 ({max_pages})，可能仍有数据未获取完成")
            
            # 对所有轨迹点按时间排序
            all_points.sort(key=lambda x: x.get('timestamp', 0))
            
            return {
                'success': True,
                'data': all_points,
                'message': f'获取轨迹完成，共 {page_count} 页，总计 {len(all_points)} 个轨迹点',
                'page_count': page_count,
                'total_points': len(all_points)
            }
                
        except Exception as e:
            logger.error(f"获取历史轨迹失败: {str(e)}")
            return {
                'success': False,
                'message': f'获取历史轨迹失败: {str(e)}',
                'page_count': page_count,
                'total_points': len(all_points)
            }
    
    def _get_single_page_track(self, mac_id: str, start_time: int, end_time: int) -> Dict[str, Any]:
        """
        获取单页历史轨迹数据（内部方法）
        """
        try:
            track_url = f"{self.api_url}/GetDateServices.asmx/GetDate"
            params = {
                'method': 'getHistoryMByMUtcNew',
                'mds': self.login_info['mds'],
                'macid': mac_id,
                'mapType': 'BAIDU',
                'from': start_time,
                'to': end_time,
                'playLBS': 'true'
            }
            
            response = self.session.get(track_url, params=params, timeout=60)
            response.raise_for_status()
            
            result = response.json()
            # logger.info(f"单页轨迹API响应: {result}")
            
            if result.get('success') == 'true':
                data_list = result.get('data', [])
                all_points = []
                
                for data_item in data_list:
                    point_str = data_item.get('Point', '')
                    if point_str:
                        points = self._parse_track_points(point_str)
                        all_points.extend(points)
                
                return {
                    'success': True,
                    'data': all_points,
                    'message': f'获取到 {len(all_points)} 个轨迹点'
                }
            else:
                return {
                    'success': False,
                    'message': result.get('errorDescribe', '获取历史轨迹失败')
                }
                
        except Exception as e:
            logger.error(f"获取单页历史轨迹失败: {str(e)}")
            return {
                'success': False,
                'message': f'获取单页历史轨迹失败: {str(e)}'
            }
    
    def _parse_location_string(self, data_str: str, device_info: Dict) -> Optional[Dict[str, Any]]:
        """
        解析字符串格式的位置数据
        """
        try:
            # 如果数据是坐标格式，如: "lng,lat,time,speed,direction"
            parts = data_str.split(',')
            if len(parts) >= 2:
                lng = float(parts[0])
                lat = float(parts[1])
                
                if lng and lat:
                    location_data = {
                        'device_time': parts[2] if len(parts) > 2 else None,
                        'device_name': device_info.get('fullName', ''),
                        'device_id': device_info.get('macid', ''),
                        'lng': lng,
                        'lat': lat,
                        'speed': float(parts[3]) if len(parts) > 3 and parts[3] else 0,
                        'location_type': 'GPS',
                        'precision': 'Unknown'
                    }
                    return location_data
            
            return None
            
        except Exception as e:
            logger.error(f"解析位置字符串失败: {str(e)}")
            return None
    
    def _parse_track_points(self, point_str: str) -> List[Dict[str, Any]]:
        """
        解析轨迹点字符串
        """
        points = []
        try:
            # 按分号分割数据
            point_segments = point_str.split(';')
            
            for segment in point_segments:
                if not segment.strip():
                    continue
                
                try:
                    # 解析单个轨迹点
                    point_data = self._parse_single_track_point(segment)
                    if point_data:
                        points.append(point_data)
                except Exception as e:
                    logger.warning(f"解析轨迹点失败: {segment}, 错误: {str(e)}")
                    continue
            
        except Exception as e:
            logger.error(f"解析轨迹点字符串失败: {str(e)}")
        
        return points
    
    def _parse_single_track_point(self, segment: str) -> Optional[Dict[str, Any]]:
        """
        解析单个轨迹点
        """
        try:
            # 分割bool和value部分
            if 'bool#' in segment:
                parts = segment.split('bool#')
                base_part = parts[0]
                bool_value_part = parts[1] if len(parts) > 1 else ''
            else:
                base_part = segment
                bool_value_part = ''
            
            # 解析基础信息: 经度,纬度,定位时间,速度,方向
            base_values = base_part.split(',')
            if len(base_values) < 5:
                return None
            
            lng = float(base_values[0])
            lat = float(base_values[1])
            timestamp = int(base_values[2])
            speed = float(base_values[3]) if base_values[3] else 0
            direction = float(base_values[4]) if base_values[4] else 0
            
            # 解析bool状态
            bool_states = []
            value_states = []
            
            if bool_value_part:
                if '$value#' in bool_value_part:
                    bool_part, value_part = bool_value_part.split('$value#', 1)
                else:
                    bool_part = bool_value_part
                    value_part = ''
                
                # 解析bool状态
                if '|' in bool_part:
                    bool_states = bool_part.split('|')
                
                # 解析value状态
                if value_part and '|' in value_part:
                    value_part = value_part.split('$')[0]  # 移除后续的extD等信息
                    value_states = value_part.split('|')
            
            # 构建轨迹点数据
            point_data = {
                'lng': lng,
                'lat': lat,
                'timestamp': timestamp,
                'speed': speed,
                'direction': direction,
                'time': timestamp_ms_to_china(timestamp).strftime('%Y-%m-%d %H:%M:%S') if timestamp else None
            }
            
            # 添加里程信息（如果有的话）
            if value_states and len(value_states) > 0 and value_states[0]:
                try:
                    point_data['mileage'] = float(value_states[0])
                except (ValueError, IndexError):
                    pass
            
            # 添加高度信息（如果有的话）
            if value_states and len(value_states) > 14 and value_states[14]:
                try:
                    point_data['altitude'] = float(value_states[14])
                except (ValueError, IndexError):
                    pass
            
            return point_data
            
        except Exception as e:
            logger.error(f"解析单个轨迹点失败: {str(e)}")
            return None